package com.nju.crawler.service;

import com.nju.crawler.repository.PersistService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @authorliyunfei
 * @date2022/12/2
 **/
@Service
public class GraphxService {

      private final static Logger LOGGER = LoggerFactory.getLogger(GraphxService.class);
      @Autowired
      private PersistService persistService;

      // userGraph{ "nodes":[{"id":,"name":},{}],"edges":[]};
      // userRepoGraph{ "nodes":[],"edges":[]};
      // 本地缓存
      private Map<String, Map<String,List<Map<String,Object>>> > graphCache = new HashMap<>(2);
      // 加载 大数据处理结果的缓存
      private Map<String,Integer> userActivityCache = new HashMap<>();
      private Map<String,Integer> userCategoryCache = new HashMap<>();
      private Map<String,Integer> repoPopularCache = new HashMap<>();
      private Map<String,String> repoRecommendCache = new HashMap<>();
      // username -> userId
      private Map<String,Integer> userNameIdCache= new HashMap<>();
      private Map<Integer,String> idUsernameCache= new HashMap<>();
      @PostConstruct
      void initCache(){
           //
           List<Map<String, Object>> userActivityList = persistService.userActivityQuery(-1);
           List<Map<String, Object>> userCategoryList = persistService.userCategoryQuery(-1);
           List<Map<String, Object>> repoPopularList = persistService.repoPopularQuery(-1);
           List<Map<String, Object>> repoRecommendList = persistService.repoRecommendQuery(-1);
           List<Map<String, Object>> userIdList = persistService.usersListQuery(5000);

           LOGGER.info("loading cache...");
           userActivityList.forEach(u->{
               userActivityCache.put((String) u.get("user_name"),(Integer) u.get("activity"));
           });
           repoPopularList.forEach(r->{
               repoPopularCache.put((String) r.get("repo_name"),(Integer) r.get("popular"));
           });
           repoRecommendList.forEach(rr->{
               repoRecommendCache.put((String) rr.get("user_name"),(String)rr.get("recommend_repo"));
           });
           userCategoryList.forEach(uc->{
               userCategoryCache.put((String) uc.get("user_name"),(Integer) uc.get("category"));
           });
           userIdList.forEach(uId->{
               userNameIdCache.put((String) uId.get("user_name"),(Integer) uId.get("user_id"));
               idUsernameCache.put((Integer) uId.get("user_id"),(String) uId.get("user_name"));
           });
           LOGGER.info("load successfully");
      }

      public void getAllGraph(){

      }

    /**
     * nodes:list<map>
     *     {
     *         id:
     *         name:
     *         symbolSize:
     *         value:
     *         category:
     *     }
     * edges:list<map>
     *     {
     *         source:
     *         target:
     *     }
     * @return
     */
    public Map<String,List<Map<String,Object>>> getUserGraph(){
        //Map<String,List<Map<String,Object>>> rs = new HashMap<>(2);
        // 枚举--
        Map<String,List<Map<String,Object>>> rsGraph = graphCache.get("userGraph");
              if(rsGraph==null){
                  rsGraph = new HashMap<>(2);
                  final int nodeNum = 100;
                  List<Map<String,Object>> nodes = new ArrayList<>(nodeNum);
                  List<Map<String,Object>> edges = new ArrayList<>();
                  // 从数据库拿数据
                  List<Map<String, Object>> userList = persistService.usersListQuery(nodeNum);
                  userList.forEach(map->{
                      //map == row
                      Integer userId = (Integer) map.get("user_id");
                      String userName = String.valueOf(map.get("user_name"));
                      String followIds = String.valueOf(map.get("follows_id"));
                      Map<String,Object> node = new HashMap<>(5);
                      node.put("id",userId);
                      node.put("name",userName);
                      int symbolSize = 5;// 2-120[大小]
                      int category = new Random().nextInt(5);// 种类
                      if(followIds!=null){
                           String[]ids = followIds.split("\\,");
                           // 处理ID的范围
                           symbolSize += (ids.length/3) ;
                           for(String each:ids){
                               Map<String,Object> edge = new HashMap<>(2);
                               edge.put("source",userId);
                               edge.put("target",each);
                               edges.add(edge);
                           }
                      }
                      node.put("category",category);
                      node.put("symbolSize",symbolSize);
                      nodes.add(node);
                      // 种类----【大数据端处理】？
                  });
                  rsGraph.put("nodes",nodes);
                  rsGraph.put("edges",edges);
                  graphCache.put("userGraph",rsGraph);
              }
        return rsGraph;
      }

    /**
     * nodes:list<map>
     *     {
     *         id:
     *         name:
     *         // 拓展信息
     *         attribute:{
     *             // 节点大小
     *             symbolSize:
     *             // 仓库流行度
     *             popular:
     *             // 用户活跃度
     *             activity:
     *             category: 0,1 (用户，仓库)
     *         }
     *         //value:
     *         //category:
     *     }
     * edges:list<map>
     *     {
     *         source:
     *         target:
     *         attribute:{
     *             relationship: star,recommand,own,
     *         }
     *     }
     */
    public Map<String,List<Map<String,Object>>> getUserRepoGraph(){
           // 领出来封装
           Map<String,List<Map<String,Object>>> rsGraph = graphCache.get("userRepoGraph");
           if(rsGraph==null){
               rsGraph = new HashMap<>(2);
               final int nodeNum = 200;
               List<Map<String,Object>> nodes = new ArrayList<>(nodeNum);
               List<Map<String,Object>> edges = new ArrayList<>();
               //List<Map<String, Object>> userRepoList= persistService.userRepoListQuery(120);

               // 图的ID并非用户ID
               AtomicInteger id = new AtomicInteger(0);
               Map<String,Integer> nameIdMap = new HashMap<>();
               // 处理节点
               int userLimit = 40;

               for(Map.Entry<String,Integer> entry:userActivityCache.entrySet()){
                   if(id.get()>=userLimit)
                       break;
                   Map<String,Object> userNode = new HashMap<>();
                   // id唯一性
                   userNode.put("id", id.getAndIncrement());
                   nameIdMap.put(entry.getKey(),id.get()-1);
                   userNode.put("name",entry.getKey());
                   Map<String,Object> extendsInfo = new HashMap<>();
                   extendsInfo.put("activity",entry.getValue());// 供前端参考处理大小显示
                   extendsInfo.put("category",0);// 0-用户，1-仓库
                   userNode.put("attribute",extendsInfo);
                   nodes.add(userNode);
               }

               final int offset = userLimit;
               final int repoLimit = 60;

               for(Map.Entry<String,Integer> entry:repoPopularCache.entrySet()){
                   if(id.get()>=offset+repoLimit)
                       break;
                   Map<String,Object> repoNode = new HashMap<>();
                   // id唯一
                   repoNode.put("id",id.getAndIncrement());
                   repoNode.put("name",entry.getKey());
                   nameIdMap.put(entry.getKey(),id.get()-1);
                   Map<String,Object> extendsInfo = new HashMap<>();
                   extendsInfo.put("popular",entry.getValue());// 供前端参考处理大小显示
                   extendsInfo.put("category",1);// 0-用户，1-仓库
                   repoNode.put("attribute",extendsInfo);
                   nodes.add(repoNode);
               }

               // 处理边
//               userRepoList.forEach(userRepo->{
//                   Integer userId = (Integer) userRepo.get("user_id") ;
//                   String repoName = (String) userRepo.get("repo_name");
//                   String type = (String) userRepo.get("type");
//                   Map<String,Object> edge = new HashMap<>(3);
//                   Map<String,Object> extendInfo = new HashMap<>();
//
//                   String userName = idUsernameCache.get(userId);
//                   Integer graphSourceId = nameIdMap.getOrDefault(userName,Integer.MAX_VALUE);
//                   Integer graphTargetId = nameIdMap.getOrDefault(repoName,Integer.MAX_VALUE);
//                   if(graphTargetId<=userLimit+repoLimit&&graphSourceId<=userLimit+repoLimit){
//                       edge.put("source",graphSourceId);
//                       edge.put("target",graphTargetId);
//                       extendInfo.put("relationship",type);
//                       edge.put("attribute",extendInfo);
//                       edges.add(edge);
//                   }
//
//               });

               // 推荐边

               repoRecommendCache.forEach((k,v)->{
                    //String userName = k;
                     String[] recommendRepos = v.split("\\;");
                     for(String each:recommendRepos){
                           Map<String,Object> edge = new HashMap<>(3);
                           Map<String,Object> edgeExtendInfo = new HashMap<>(1);
                           Integer graphSourceId = nameIdMap.getOrDefault(k,Integer.MAX_VALUE);
                           Integer graphTargetId = nameIdMap.getOrDefault(each,Integer.MAX_VALUE);
                           if(graphTargetId<=userLimit+repoLimit&&graphSourceId<=userLimit+repoLimit){
                               edge.put("source",graphSourceId);
                               edge.put("target",graphTargetId);
                               edgeExtendInfo.put("relationship","recommend");
                               edgeExtendInfo.put("sourceName",k);
                               edgeExtendInfo.put("targetName",each);
                               edge.put("attribute",edgeExtendInfo);
                               edges.add(edge);
                           }
                     }
               });

               rsGraph.put("nodes",nodes);
               rsGraph.put("edges",edges);
           }

           return rsGraph;
    }

    /**
     * nodes:list<map>
     *     {
     *         id:
     *         name:
     *         symbolSize:
     *         value:
     *         category:
     *     }
     * edges:list<map>
     *     {
     *         source:
     *         target:
     *     }
     * @param newUserGraph
     * @return
     */
      public boolean updateUserGraph(Map<String,List<Map<String,Object>>> newUserGraph){
             graphCache.put("userGraph",newUserGraph);
             return true;
      }
      public void updateUserRepoGraph(){

      }

}
